package cn.com.shopec.erp.stock.service.impl;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import cn.com.shopec.erp.base.dao.ISupplierInfoDao;
import cn.com.shopec.erp.common.constant.ProductSCMConstant;
import cn.com.shopec.erp.common.constant.SZSCMConstant;
import cn.com.shopec.erp.common.page.PageFinder;
import cn.com.shopec.erp.common.page.PageQuery;
import cn.com.shopec.erp.common.utils.DateUtil;
import cn.com.shopec.erp.common.utils.IntegerUtil;
import cn.com.shopec.erp.common.utils.LongUtil;
import cn.com.shopec.erp.common.utils.NoUtil;
import cn.com.shopec.erp.common.utils.StringUtil;
import cn.com.shopec.erp.multiChannel.service.IChannelOrderService;
import cn.com.shopec.erp.product.dao.ICommodityDao;
import cn.com.shopec.erp.product.dao.IProductDao;
import cn.com.shopec.erp.product.dao.IProductStockDao;
import cn.com.shopec.erp.product.entity.Defective;
import cn.com.shopec.erp.product.entity.ProductStock;
import cn.com.shopec.erp.product.service.IDefectReplceService;
import cn.com.shopec.erp.product.service.IDefectiveService;
import cn.com.shopec.erp.purchase.entity.StockPurchase;
import cn.com.shopec.erp.purchase.service.IPurchaseOrderService;
import cn.com.shopec.erp.purchase.service.IPurchaseReturnOrderService;
import cn.com.shopec.erp.purchase.service.IStockPurchaseService;
import cn.com.shopec.erp.stock.commo.ObjectUtil;
import cn.com.shopec.erp.stock.commo.StockHistroyUtil;
import cn.com.shopec.erp.stock.commo.StockInUtil;
import cn.com.shopec.erp.stock.commo.StockProductException;
import cn.com.shopec.erp.stock.dao.IProductBarCodeDao;
import cn.com.shopec.erp.stock.dao.IStockHistoryDao;
import cn.com.shopec.erp.stock.dao.IStockInDao;
import cn.com.shopec.erp.stock.dao.IStockInProductDao;
import cn.com.shopec.erp.stock.dao.IStockOutPurInfoDao;
import cn.com.shopec.erp.stock.entity.StockHistory;
import cn.com.shopec.erp.stock.entity.StockIn;
import cn.com.shopec.erp.stock.entity.StockInProduct;
import cn.com.shopec.erp.stock.service.IStockInService;
import cn.com.shopec.erp.stock.vo.StockInProductVo;
import cn.com.shopec.erp.stock.vo.StockInVo;
import cn.com.shopec.erp.system.common.UserUtils;
import cn.com.shopec.erp.warehouse.service.IStockTransferService;

/**
 * @ClassName: StockInServiceImpl.java
 * @Description: 入库信息service接口实现类
 * @author: zengxuezhou
 * @date: 2016年11月28日 下午2:30:52
 */
@Service
public class StockInServiceImpl implements IStockInService {

	@Resource
	private IStockInDao stockInDao;

	@Resource
	private ICommodityDao commodityDao;

	@Resource
	private IStockInProductDao stockInProductDao;

	@Resource
	private IProductDao productDao;

	@Resource
	private IProductStockDao productStockDao;

	@Resource
	private ISupplierInfoDao supplierInfoDao;

	@Resource
	private IStockHistoryDao stockHistoryDao;

	@Resource
	private IPurchaseOrderService purchaseOrderService;

	@Resource
	private IProductBarCodeDao productBarCodeDao;

	@Resource
	private IPurchaseReturnOrderService purchaseReturnOrderService;

	@Resource
	private IDefectiveService defectiveService;

	@Resource
	private IChannelOrderService channelOrderService;

	@Resource
	private IDefectReplceService defectReplceService;

	@Resource
	IStockPurchaseService stockPurchaseService;

	@Resource
	private IStockTransferService stockTransferService;

	@Resource
	private IStockOutPurInfoDao stockOutPurInfoDao;

	@Override
	public PageFinder<StockInVo> queryStockList(StockInVo stockIn, PageQuery pageQuery) {
		PageFinder<StockIn> poageFinder = stockInDao.pagedByCriteria(getQueryCriteria(stockIn), pageQuery.getPage(),
				pageQuery.getPageSize());
		return getStockInVoPageFinder(poageFinder);
	}

	@Override
	public List<StockInVo> queryStockListByFinder(StockInVo stockIn) {
		List<StockIn> list = stockInDao.findByCriteria(getQueryCriteria(stockIn));
		List<StockInVo> result = new ArrayList<StockInVo>();
		if (list != null && list.size() > 0) {
			for (StockIn obj : list) {
				StockInVo stockInVo = StockInUtil.parseStockVo(obj);
				StockInVo stockInTemp = stockInDao.queryWarehouseAndSupplier(obj.getStockInNo());
				stockInVo.setWhName(stockInTemp.getWhName());
				stockInVo.setSupName(stockInTemp.getSupName());
				result.add(stockInVo);
			}
		}
		return result;
	}

	/**
	 * 设置查询入库信息的条件
	 * 
	 * @param stockIn
	 * @return
	 */
	private DetachedCriteria getQueryCriteria(StockInVo stockIn) {
		DetachedCriteria detachedCriteria = stockInDao.createCriteria();

		if (StringUtil.isExist(stockIn.getStockInNo())) {// 入库单编号
			detachedCriteria.add(Restrictions.like("stockInNo", stockIn.getStockInNo(), MatchMode.ANYWHERE));
		}
		if (ObjectUtil.isNotNull(stockIn.getStockInType())) {// 入库单类型
			detachedCriteria.add(Restrictions.eq("stockInType", stockIn.getStockInType()));
		}
		if (StringUtil.isExist(stockIn.getBeginTime())) {// 出入库起始时间
			detachedCriteria.add(Restrictions.ge("createTime", DateUtil.parseTimesTampDate(stockIn.getBeginTime())));
		}
		if (StringUtil.isExist(stockIn.getEndTime())) {// 出入库结束时间
			detachedCriteria.add(Restrictions.le("createTime", DateUtil.parseTimesTampDate(stockIn.getEndTime())));
		}
		if (StringUtil.isExist(stockIn.getPurNo())) {// 采购单
			detachedCriteria.add(Restrictions.like("purNo", stockIn.getPurNo(), MatchMode.ANYWHERE));
		}
		if (StringUtil.isExist(stockIn.getWhNo())) {// 仓库
			detachedCriteria.add(Restrictions.eq("whNo", stockIn.getWhNo()));
		}
		detachedCriteria.add(Restrictions.eq("deletedFlag", SZSCMConstant.DELETE_FLAG_NO));
		detachedCriteria.addOrder(Order.desc("createTime"));
		return detachedCriteria;
	}

	/**
	 * 根据PageFinder<StockIn>拼装PageFinder<StockInVo>
	 * 
	 * @param pageFinders
	 * @return
	 */
	private PageFinder<StockInVo> getStockInVoPageFinder(PageFinder<StockIn> pageFinders) {
		List<StockInVo> stockInVos = new ArrayList<StockInVo>();
		List<StockIn> stockIns = pageFinders.getData();
		for (StockIn stockIn : stockIns) {
			StockInVo stockInVo = StockInUtil.parseStockVo(stockIn);
			StockInVo stockInTemp = stockInDao.queryWarehouseAndSupplier(stockIn.getStockInNo());
			stockInVo.setWhName(stockInTemp.getWhName());
			stockInVo.setSupName(stockInTemp.getSupName());
			stockInVos.add(stockInVo);
		}
		PageFinder<StockInVo> result = new PageFinder<StockInVo>(pageFinders.getPageNo(), pageFinders.getPageSize(),
				pageFinders.getRowCount());
		result.setData(stockInVos);
		return result;
	}

	@Override
	public PageFinder<StockInProductVo> queryStockProductList(StockInVo stockIn, PageQuery pageQuery) {
		int count = stockInProductDao.getProductsCountByStockNo(stockIn.getStockInNo());
		PageFinder<StockInProductVo> result = new PageFinder<StockInProductVo>(pageQuery.getPage(),
				pageQuery.getPageSize(), count);
		if (count > 0) {
			List<StockInProductVo> stockOutVos = stockInProductDao.getProductsListByStockNo(stockIn.getStockInNo(),
					result.getStartOfPage(), result.getPageSize());
			result.setData(stockOutVos);
		}
		return result;
	}

	@Override
	public StockInVo getStockByNo(String stockInNo) {

		return stockInDao.getStockByNo(stockInNo);
	}

	@Override
	@Transactional
	public boolean addStockIns(StockInVo stockInVo, List<StockInProductVo> stockInProductVos) throws Exception {
		List<StockIn> stockIns = new ArrayList<StockIn>();// 存放入库单集合,用于划分仓库
		for (StockInProductVo stockInProductVo : stockInProductVos) {
			String whNo = ObjectUtil.toString(stockInProductVo.getWhNo());
			String supNo = ObjectUtil.toString(stockInProductVo.getSupNo());
			StockIn stockIn = null;
			for (StockIn temp : stockIns) {
				// 区分仓库和供应商，如果在入库单集合中存在则返回对应的入库单
				String whNoTemp = ObjectUtil.toString(temp.getWhNo());
				String supTemp = ObjectUtil.toString(temp.getSupNo());
				if (whNo.equals(whNoTemp) && supNo.equals(supTemp)) {
					stockIn = temp;
					break;
				}
			}
			if (ObjectUtil.isNull(stockIn)) {// 判断上面的迭代是否给返回stockIn，如果没有则新建一条.
				stockIn = StockInUtil.parseStockIn(stockInVo);
				stockIn.setStockInNo(NoUtil.getNo(NoUtil.STOCKIN_NO));
				stockIn.setWhNo(whNo);
				stockIn.setSupNo(supNo);
				stockIns.add(stockIn);// 放进入库单集合中，用于区分下一次迭代判断是否存在该仓库
				addStock(stockIn);// 新增入库单入数据库
			}
			stockInProductVo.setStockInNo(stockIn.getStockInNo());// 设置入库单与入库商品的关联关系
			StockInProduct stockInProduct = StockInUtil.parseStockInProduct(stockInProductVo);
			stockInProduct.setPurNo(stockIn.getPurNo());
			stockInProduct.setSupNo(stockIn.getSupNo());
			stockInProduct.setSupName(stockInVo.getSupName());
			addStockInProduct(stockInProduct);// 新增入库单商品入数据库
		}
		updateRelatedBillStateForAdd(stockInVo);
		return true;
	}

	@Override
	@Transactional
	public boolean addStockInForTransfer(StockInVo stockInVo, List<StockInProduct> stockInProducts) throws Exception {
		if (ObjectUtil.isNotNull(stockInVo)) {
			stockInVo.setStockInNo(NoUtil.getNo(NoUtil.STOCKIN_NO));
			StockIn stockIn = StockInUtil.parseStockIn(stockInVo);
			addStock(stockIn);
			addStockInProduct(stockInVo, stockInProducts);
			stockTransferService.setStockInFlowState(stockInVo.getStockInTypeNo());
			return true;
		}
		return true;
	}

	/**
	 * 修改相关单据状态
	 * 
	 * @param stockInVo
	 * @throws Exception
	 */
	@Transactional
	void updateRelatedBillStateForAdd(StockInVo stockInVo) throws Exception {
		Integer stockInType = stockInVo.getStockInType();
		if (ObjectUtil.isNotNull(stockInType)) {
			if (stockInType.equals(SZSCMConstant.STOCKIN_TYPE_1)) {
				purchaseOrderService.updateAuditResultPurchaseOrder(stockInVo.getPurNo(),
						ProductSCMConstant.PO_STATUS_FOUR);
			} else if (stockInType.equals(SZSCMConstant.STOCKIN_TYPE_2)) {
				channelOrderService.updateProductPackageReturnState(stockInVo.getStockInTypeNo(), SZSCMConstant.CHANNEL_ORDER_RETURN_STATE_3);// 改变订单退货状态
			} else if (stockInType.equals(SZSCMConstant.STOCKIN_TYPE_3)) {
				defectReplceService.updateAuditResultDefectReplce(stockInVo.getStockInTypeNo(),
						ProductSCMConstant.DEFECTREPLCE_STATE_4);
			} else if (stockInType.equals(SZSCMConstant.STOCKIN_TYPE_4)) {
				purchaseReturnOrderService.updateAuditResultPurchaseOrder(stockInVo.getStockInTypeNo(),
						ProductSCMConstant.PURCHASERETURN_STATUS_FIVE);
			} else if (stockInType.equals(SZSCMConstant.STOCKIN_TYPE_5)) {
				stockTransferService.setStockInFlowState(stockInVo.getStockInTypeNo());
			}
		}
	}

	/**
	 * 只增加入库基础信息
	 * 
	 * @param stockIn
	 * @throws Exception
	 */
	@Transactional
	private void addStock(StockIn stockIn) throws Exception {
		stockIn.setId(null);
		stockIn.setDeletedFlag(SZSCMConstant.DELETE_FLAG_NO);
		stockIn.setStockInState(SZSCMConstant.STOCK_STATE_NO);
		stockIn.setCreater(UserUtils.getLoginUserName());
		stockIn.setCreateTime(DateUtil.getCurrentDate());
		stockInDao.save(stockIn);
	}

	@Override
	@Transactional
	public boolean approveStockIn(StockInVo stockInVo, List<StockInProductVo> stockInProducts) throws Exception {

		StockIn stockIn = stockInDao.get("stockInNo", stockInVo.getStockInNo());// 查询入库单基础信息
		if (ObjectUtil.eq(stockIn.getStockInState(), SZSCMConstant.STOCK_STATE_NO)
				&& ObjectUtil.eq(stockIn.getDeletedFlag(), SZSCMConstant.DELETE_FLAG_NO)) {// 判断是否为有效信息
			if (!CollectionUtils.isEmpty(stockInProducts)) {// 判断入库单是否拥有产品
				StockInVo stockInVoTemp = stockInDao.queryWarehouseAndSupplier(stockInVo.getStockInNo());
				stockInVo = StockInUtil.parseStockVo(stockIn);
				stockInVo.setWhName(stockInVoTemp.getWhName());
				stockInVo.setSupName(stockInVoTemp.getSupName());
				return beginApproveStockIn(stockIn, stockInVo, stockInProducts);
			}

		}
		return false;
	}

	/**
	 * 开始正式入库（入库审核）
	 * 
	 * @param stockIn
	 * @param stockInProducts
	 * @return
	 * @throws Exception
	 */
	@Transactional
	private boolean beginApproveStockIn(StockIn stockIn, StockInVo stockInVo, List<StockInProductVo> stockInProductVos)
			throws Exception {
		List<Defective> defectives = new ArrayList<Defective>();
		updateStockInForApprove(stockInVo.getStockInNo());// 更新入库信息
		for (StockInProductVo stockInProductVo : stockInProductVos) {

			updateStockInProductForApprove(stockInVo, stockInProductVo);// 更新入库商品信息

			ProductStock productStock = saveProductStockForStockIn(stockInVo, stockInProductVo);// 保存到库存中

			saveStockPurchase(stockInVo, stockInProductVo, productStock);// 维护采购单库存关联信息

			saveStockHistory(stockInVo, stockInProductVo, productStock);// 保存库存变更记录信息

			setDefectivesList(defectives, stockInVo, stockInProductVo);// 获取次品信息

			updateRelatedBillStateForApprove(stockInVo);// 修改关联单据状态信息
		}

		saveDefective(defectives);// 保存入库次品信息
		return true;
	}

	@Override
	@Transactional
	public boolean approveStockInForTransfer(StockInVo stockInVo, List<StockInProductVo> stockInProductVos)
			throws Exception {
		stockInVo = stockInDao.getStockByNo(stockInVo.getStockInNo());// 查询入库单基础信息
		if (ObjectUtil.eq(stockInVo.getStockInState(), SZSCMConstant.STOCK_STATE_NO)
				&& ObjectUtil.eq(stockInVo.getDeletedFlag(), SZSCMConstant.DELETE_FLAG_NO)) {// 判断是否为有效信息
			if (!CollectionUtils.isEmpty(stockInProductVos)) {// 判断入库单是否拥有产品
				updateStockInForApprove(stockInVo.getStockInNo());// 更新入库信息
				for (StockInProductVo stockInProductVo : stockInProductVos) {
					updateStockInProductForApprove(stockInVo, stockInProductVo);// 更新入库商品信息

					ProductStock productStock = saveProductStockForStockIn(stockInVo, stockInProductVo);// 保存到库存中

					saveStockPurchase(stockInVo, stockInProductVo, productStock);// 维护采购单库存关联信息

					saveStockHistory(stockInVo, stockInProductVo, productStock);// 保存库存变更记录信息

					updateProductBarCodeForTransfer(stockInVo);// 调拨后原条码信息所在仓库信息将改变
					
					updateRelatedBillStateForApprove(stockInVo);// 修改关联单据状态信息

				}
				return true;
			}
		}
		return false;
	}

	/**
	 * 修改条码信息（调拨用）
	 * @param stockInVo
	 */
	private void updateProductBarCodeForTransfer(StockInVo stockInVo) {
		// TODO Auto-generated method stub
		productBarCodeDao.updateProductBarCodeForTransfer(stockInVo.getStockInTypeNo(),stockInVo.getWhNo(),stockInVo.getWhName());
	}

	/**
	 * 修改相关单据状态
	 * 
	 * @param stockIn
	 * @throws Exception
	 */
	@Transactional
	void updateRelatedBillStateForApprove(StockInVo stockIn) throws Exception {
		Integer stockInType = stockIn.getStockInType();
		if (ObjectUtil.isNotNull(stockInType)) {
			if (stockInType.equals(SZSCMConstant.STOCKIN_TYPE_1)) {
				updatePurchaseOrderForStockIn(stockIn);
			} else if (stockInType.equals(SZSCMConstant.STOCKIN_TYPE_2)) {
				updateChannelOrderForStockIn(stockIn);
			} else if (stockInType.equals(SZSCMConstant.STOCKIN_TYPE_3)) {
				defectReplceService.updateAuditResultDefectReplce(stockIn.getStockInTypeNo(),
						ProductSCMConstant.DEFECTREPLCE_STATE_5);
			} else if (stockInType.equals(SZSCMConstant.STOCKIN_TYPE_4)) {
				purchaseReturnOrderService.updateAuditResultPurchaseOrder(stockIn.getStockInTypeNo(),
						ProductSCMConstant.PURCHASERETURN_STATUS_SIX);
			} else if (stockInType.equals(SZSCMConstant.STOCKIN_TYPE_5)) {
				stockTransferService.setStockInFinishFlowState(stockIn.getStockInTypeNo());
			}
		}
	}

	/**
	 * 入口单商品内有次品的数据转换为次品信息并且放入list中
	 * 
	 * @param defectives
	 * @param stockInVo
	 * @param stockInProductVo
	 * @param stockPurchase
	 */
	@Transactional
	private void setDefectivesList(List<Defective> defectives, StockInVo stockInVo, StockInProductVo stockInProductVo) {
		if (LongUtil.gtZero(stockInProductVo.getDefectiveQuantity())) {
			Defective defective = StockInUtil.parseDefective(stockInVo, stockInProductVo);
			defectives.add(defective);
		}
	}

	/**
	 * 修改采购单据为已入库
	 * 
	 * @param stockIn
	 * @throws Exception
	 */
	@Transactional
	private void updatePurchaseOrderForStockIn(StockInVo stockIn) throws Exception {
		String purNo = stockIn.getPurNo();
		if (!StringUtil.isEmpty(purNo)) {
			int count = getUnaduitDataCountByPurchase(purNo);
			if (IntegerUtil.eqZero(count)) {
				purchaseOrderService.updateAuditResultPurchaseOrder(purNo, ProductSCMConstant.PO_STATUS_SEX);
			} else {
				purchaseOrderService.updateAuditResultPurchaseOrder(purNo, ProductSCMConstant.PO_STATUS_FIVE);
			}
		}
	}

	/**
	 * 修改订单为已入库
	 *
	 * @param stockIn
	 * @throws Exception 
	 */
	@Transactional
	private void updateChannelOrderForStockIn(StockInVo stockIn) throws Exception {
		String stockInTypeNo = stockIn.getStockInTypeNo();
		if (!StringUtil.isEmpty(stockInTypeNo)) {
			int count = getUnaduitDataCountByStockInType(stockIn);
			if (IntegerUtil.eqZero(count)) {
				channelOrderService.updateProductPackageReturnState(stockIn.getStockInTypeNo(), SZSCMConstant.CHANNEL_ORDER_RETURN_STATE_1);// 改变订单退货状态
			}
		}
	}

	/**
	 * 入库存时更新入库单信息
	 * 
	 * @param stockIn
	 * @throws Exception
	 */
	@Transactional
	void updateStockInForApprove(String stockInNo) throws Exception {
		stockInDao.updateStockInForApprove(stockInNo);
	}

	/**
	 * 入库存时更新入库单商品信息
	 *
	 * @param stockIn
	 * @param stockInProductVo
	 * @throws Exception
	 */
	@Transactional
	void updateStockInProductForApprove(StockInVo stockIn, StockInProductVo stockInProductVo) throws Exception {
		StockInProduct stockInProduct = StockInUtil.parseStockInProduct(stockInProductVo);
		stockInProduct.setDefectiveReason(stockInProductVo.getDefectiveReason());
		stockInProduct.setDeletedFlag(SZSCMConstant.DELETE_FLAG_NO);
		stockInProduct.setUpdater(stockIn.getUpdater());
		stockInProduct.setUpdateTime(DateUtil.getCurrentDate());
		stockInProductDao.update(stockInProduct);
	}

	/**
	 * 保存入库次品信息
	 * 
	 * @param defectives
	 * @throws Exception
	 */
	@Transactional
	void saveDefective(List<Defective> defectives) throws Exception {
		if (IntegerUtil.gtZero(defectives.size())) {
			defectiveService.addDefective(defectives);
		}
	}

	/**
	 * 保存库存变更记录信息
	 * 
	 * @param stockIn
	 * @param stockInProductVo
	 * @param productStock
	 * @throws Exception
	 */
	@Transactional
	void saveStockHistory(StockInVo stockIn, StockInProductVo stockInProductVo, ProductStock productStock)
			throws Exception {
		StockHistory stockHistory = StockHistroyUtil.parseStockHistory(stockIn, stockInProductVo, productStock);
		stockHistoryDao.save(stockHistory);
	}

	/**
	 * 根据各类型入库信息选择保存采购单库存信息
	 * 
	 * @param stockIn
	 * @param stockInProductVo
	 * @param productStock
	 * @throws Exception
	 */
	@Transactional
	void saveStockPurchase(StockInVo stockIn, StockInProductVo stockInProductVo, ProductStock productStock)
			throws Exception {
		StockPurchase stockPurchase = null;
		Integer stockInType = stockIn.getStockInType();
		if (ObjectUtil.eq(stockInType, SZSCMConstant.STOCKIN_TYPE_1)) {
			stockPurchase = StockInUtil.parseStockPurchase(stockIn, productStock, stockInProductVo);
			stockPurchaseService.addPurchaseStock(stockPurchase);
		}else if (ObjectUtil.eq(stockInType, SZSCMConstant.STOCKIN_TYPE_2)){
		//	saveStockPurchaseForOrder(stockIn, stockInProductVo,productStock);
		} else if (ObjectUtil.eq(stockInType, SZSCMConstant.STOCKIN_TYPE_3)
				|| ObjectUtil.eq(stockInType, SZSCMConstant.STOCKIN_TYPE_4)) {
			saveStockPurchaseForReturn(stockIn, stockInProductVo);
		} else if (ObjectUtil.eq(stockInType, SZSCMConstant.STOCKIN_TYPE_5)) {
			saveStockPurchaseForTransfer(stockIn, stockInProductVo, productStock);
		}
	}

	/**
	 * 维护采购单库存信息(订单换货入库用)
	 * @param stockIn
	 * @param stockInProductVo
	 * @throws Exception 
	 */
	@Transactional
	private void saveStockPurchaseForOrder(StockInVo stockIn, StockInProductVo stockInProductVo,ProductStock productStock) throws Exception {
		List<Object[]> purInfos = null;//该集合内数组只有两个，[0]为采购单号，[1]为商品数量
		if (ObjectUtil.eq(stockInProductVo.getProductCodeState(), SZSCMConstant.PRODUCT_PUR_STATE_1)) {//根据调拨出库时是导入条形码，选择采购单。来获取对应的采购单号和数量
			purInfos = productBarCodeDao.queryForStockIn(stockInProductVo.getId());
		} else if (ObjectUtil.eq(stockInProductVo.getProductCodeState(), SZSCMConstant.PRODUCT_PUR_STATE_2)) {
			purInfos = stockOutPurInfoDao.queryForStockIn(stockInProductVo.getId());
		}
		saveStockPurchase(stockIn, stockInProductVo, productStock, purInfos);
	}
	
	/**
	 * 维护采购单库存信息(次品换货入库，采购单换货入库用)
	 * 
	 * @param stockIn
	 * @param stockInProductVo
	 * @param productStock
	 * @throws Exception
	 */
	@Transactional
	private void saveStockPurchaseForReturn(StockInVo stockIn, StockInProductVo stockInProductVo) throws Exception {
		StockPurchase stockPurchase;
		stockPurchase = new StockPurchase();
		stockPurchase.setPoNo(stockIn.getPurNo());
		stockPurchase.setProdNo(stockInProductVo.getProdNo());
		stockPurchase.setWhNo(stockInProductVo.getWhNo());
		stockInProductVo.getDefectiveQuantity();
		stockPurchase.setYieldAmountNumner(LongUtil.valuesOf(stockInProductVo.getQualifiedQuantity()));
		stockPurchase.setDefectiveAmountNumber(LongUtil.valuesOf(stockInProductVo.getDefectiveQuantity()));
		stockPurchaseService.changeQuantity(stockPurchase);
	}

	/**
	 * 维护采购单库存信息（调拨用）
	 * 
	 * @param stockIn
	 * @param stockInProductVo
	 * @param productStock
	 * @throws Exception
	 */
	@Transactional
	private void saveStockPurchaseForTransfer(StockInVo stockIn, StockInProductVo stockInProductVo,
			ProductStock productStock) throws Exception {
		List<Object[]> purInfos = null;//该集合内数组只有两个，[0]为采购单号，[1]为商品数量
		if (ObjectUtil.eq(stockInProductVo.getProductCodeState(), SZSCMConstant.PRODUCT_PUR_STATE_1)) {//根据调拨出库时是导入条形码，选择采购单。来获取对应的采购单号和数量
			purInfos = productBarCodeDao.queryForStockTransfer(stockIn.getStockInTypeNo(),
					stockInProductVo.getProdNo());
		} else if (ObjectUtil.eq(stockInProductVo.getProductCodeState(), SZSCMConstant.PRODUCT_PUR_STATE_2)) {
			purInfos = stockOutPurInfoDao.queryForStockTransfer(stockIn.getStockInTypeNo(),
					stockInProductVo.getProdNo());
		}
		saveStockPurchase(stockIn, stockInProductVo, productStock, purInfos);
	}
	
	/**
	 * 存储采购单关联信息
	 * @param stockIn
	 * @param stockInProductVo
	 * @param productStock
	 * @param purInfos
	 * @throws Exception
	 */
	@Transactional
	private void saveStockPurchase(StockInVo stockIn, StockInProductVo stockInProductVo, ProductStock productStock,
			List<Object[]> purInfos) throws Exception {
		if (CollectionUtils.isEmpty(purInfos)) {//原（采购单，条码）信息不存在时，抛错
			throw new StockProductException(stockInProductVo, purInfos);
		}
		StockPurchase stockPurchase = new StockPurchase();
		stockPurchase.setProdNo(stockInProductVo.getProdNo());
		stockPurchase.setWhNo(stockIn.getWhNo());
		for (Object[] objects : purInfos) {
			stockPurchase.setPoNo(objects[0].toString());
			StockPurchase stockPurchaseTemp = stockPurchaseService.getProductPoNo(stockPurchase);
			if (ObjectUtil.isNotNull(stockPurchaseTemp)) {//判断入库的仓库是否已经拥有该采购单关联信息的数据（有改，无增）
				stockPurchase.setYieldAmountNumner(ObjectUtil.toLong(objects[1]));
				stockPurchase.setDefectiveAmountNumber(0L);
				stockPurchaseService.changeQuantity(stockPurchase);
			} else {
				stockPurchase = StockInUtil.parseStockPurchase(stockIn, productStock, stockInProductVo);
				stockPurchase.setPoNo(objects[0].toString());
				stockPurchaseService.addPurchaseStock(stockPurchaseTemp);
			}
		}
	}

	/**
	 * 保存到库存信息，返回数据库存储的数据对象
	 * 
	 * @param stockInProductVo
	 * @param stockIn
	 * 
	 * @param productStock
	 * @return
	 * @throws Exception
	 */
	@Transactional
	private ProductStock saveProductStockForStockIn(StockInVo stockInVo, StockInProductVo stockInProductVo)
			throws Exception {
		ProductStock productStock = StockInUtil.parseProductStock(stockInVo, stockInProductVo);
		productStock.setUpdateTime(DateUtil.getCurrentDate());
		ProductStock productStockFromDB = productStockDao.findUniqueProduct(productStock);
		if (ObjectUtil.isNotNull(productStockFromDB)) {
			long qualifiedQuantity = productStockFromDB.getQualifiedQuantity() + productStock.getQualifiedQuantity();
			long defectiveQuantity = productStockFromDB.getDefectiveQuantity() + productStock.getDefectiveQuantity();
			long productTotal = qualifiedQuantity + defectiveQuantity;
			productStockFromDB.setQualifiedQuantity(qualifiedQuantity);
			productStockFromDB.setDefectiveQuantity(defectiveQuantity);
			productStockFromDB.setProductTotal(productTotal);
			productStockFromDB.setUpdateTime(productStock.getUpdateTime());
			productStockDao.update(productStockFromDB);
			return productStockFromDB;
		} else {
			productStockDao.save(productStock);
			return productStock;
		}
	}

	/**
	 * 根据采购单获取未验证的入库单数量
	 * 
	 * @param purNo
	 * @return
	 */
	@Transactional
	private int getUnaduitDataCountByPurchase(String purNo) {
		DetachedCriteria detachedCriteria = stockInDao.createCriteria();
		detachedCriteria.add(Restrictions.eq("purNo", purNo));
		detachedCriteria.add(Restrictions.eq("stockInState", SZSCMConstant.STOCK_STATE_NO));
		detachedCriteria.add(Restrictions.eq("deletedFlag", SZSCMConstant.DELETE_FLAG_NO));
		return stockInDao.getCountByCriteria(detachedCriteria);
	}

	/**
	 * 根据类型和类型单号获取未入库的入库单数量
	 * 
	 * @param purNo
	 * @return
	 */
	@Transactional
	private int getUnaduitDataCountByStockInType(StockInVo stockIn) {
		DetachedCriteria detachedCriteria = stockInDao.createCriteria();
		detachedCriteria.add(Restrictions.eq("stockInType", stockIn.getStockInType()));
		detachedCriteria.add(Restrictions.eq("stockInTypeNo", stockIn.getStockInTypeNo()));
		detachedCriteria.add(Restrictions.eq("stockInState", SZSCMConstant.STOCK_STATE_NO));
		detachedCriteria.add(Restrictions.eq("deletedFlag", SZSCMConstant.DELETE_FLAG_NO));
		return stockInDao.getCountByCriteria(detachedCriteria);
	}

	/**
	 * 增加入库信息中的商品
	 * 
	 * @param stockInProduct
	 * @throws Exception
	 */
	@Transactional
	private void addStockInProduct(StockInProduct stockInProduct) throws Exception {
		stockInProduct.setId(null);
		stockInProduct.setCreater(UserUtils.getLoginUserName());
		stockInProduct.setCreateTime(DateUtil.getCurrentDate());
		stockInProduct.setDeletedFlag(SZSCMConstant.DELETE_FLAG_NO);
		stockInProductDao.save(stockInProduct);
	}

	/**
	 * 批量增加入库信息中的商品
	 * 
	 * @param stockInNo
	 * @param stockInProducts
	 * @return
	 * @throws Exception
	 */
	@Transactional
	private boolean addStockInProduct(StockInVo stockInVo, List<StockInProduct> stockInProducts) throws Exception {
		if (ObjectUtil.isNotNull(stockInVo) && !CollectionUtils.isEmpty(stockInProducts)) {
			for (StockInProduct stockInProduct : stockInProducts) {
				stockInProduct.setStockInNo(stockInVo.getStockInNo());
				if(!ObjectUtil.eq(stockInVo.getStockInType(),SZSCMConstant.STOCKIN_TYPE_5)){
					stockInProduct.setPurNo(stockInVo.getPurNo());
					stockInProduct.setSupNo(stockInVo.getSupNo());
					stockInProduct.setSupName(stockInVo.getSupName());
				}
				addStockInProduct(stockInProduct);
			}
			return true;
		}
		return false;
	}

	/**
	 * 修改入库信息中的商品
	 * 
	 * @param stockInNo
	 * @param stockInProducts
	 * @return
	 * @throws Exception
	 */
	@Transactional
	private boolean updateStockInProduct(StockInVo stockInVo, List<StockInProduct> stockInProducts) throws Exception {
		boolean isRemove = stockInProductDao.removeForUpdate(stockInVo.getStockInNo());
		if (isRemove) {
			return addStockInProduct(stockInVo, stockInProducts);
		}
		return false;
	}

	/**
	 * 删除入库单
	 */
	@Override
	@Transactional
	public boolean deleteStockIn(String stockInNo) throws Exception {
		if (StringUtils.isNotEmpty(stockInNo)) {
			StockIn stockIn = stockInDao.get("stockInNo", stockInNo);
			if (ObjectUtil.isNotNull(stockIn)) {
				stockIn.setDeletedFlag(SZSCMConstant.DELETE_FLAG_YES);
				stockInDao.update(stockIn);
				stockInProductDao.removeProductByStockInNo(stockInNo);
				return true;
			}
		}
		return false;
	}

	/**
	 * 删除入库商品
	 */
	@Override
	@Transactional
	public boolean deleteStockInProduct(String id) throws Exception {
		if (StringUtils.isNotEmpty(id)) {
			StockInProduct stockIn = stockInProductDao.get("id", id);
			if (ObjectUtil.isNotNull(stockIn)) {
				stockIn.setDeletedFlag(SZSCMConstant.DELETE_FLAG_YES);
				stockInProductDao.update(stockIn);
				return true;
			}
		}
		return false;
	}

}
